#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <omp.h>
#include "palindromo.h"

#define ARQUIVO 	"./arq/shakespe.txt"
#define ARQ_PALI	"./resultados/shak_pal_omp.txt"

#ifndef TBLOCO
#define TBLOCO 4
#endif

#ifndef NTHREADS
#define NTHREADS 4
#endif

#define TAM_BUFF NTHREADS*TBLOCO*1024 


char buffer1[TAM_BUFF];
char buffer2[TAM_BUFF];
int palavras, palindromos, frases, frasespal;
int tam[NTHREADS];

//Busca os palindromos no bloco de texto
void busca_no_bloco(int lido){
	int pala, palip, fras, palif; 
	int fplflag, pplflag, th;
	int iniciop, fimp, max;
	int iniciof, fimf;

	pala = palip = fras = palif = 0;
	
	//divisão dos processos
	#pragma omp parallel reduction(+: pala, palip, fras, palif) private(th, fplflag, pplflag, iniciop, fimp, max, iniciof, fimf)
	{

		//Cada thread fica com uma parte do bloco
		th = omp_get_thread_num();
		tam[th] = iniciof =  1024 * TBLOCO * th;
		max = (1024 * TBLOCO) + iniciof;
		if(lido < max) max = lido;

		//encontra o inicio da primeira frase
		while(iniciof < max &&
		(buffer1[iniciof] == '\n' || buffer1[iniciof] == '\r' || buffer1[iniciof] == '.' || 
		 buffer1[iniciof] == ':' || buffer1[iniciof] == ';' || buffer1[iniciof] == '?' ||
		 buffer1[iniciof] == '!')) iniciof++;

		while(iniciof < max){
			//encontra o fim da frase
			fimf = iniciof;
			while(fimf < max && buffer1[fimf] != '\n' && buffer1[fimf] != '\r'
				&& buffer1[fimf] != '.' && buffer1[fimf] != ':' && buffer1[fimf] != ';'
				&& buffer1[fimf] != '?' && buffer1[fimf] != '!') fimf++;

			if(fimf == max) break;

			//soma a frase e verifica se é palindromo
			fras++;
			fplflag = check_frase( buffer1 + iniciof, fimf - iniciof);

			//se for palindromo conta e salva no seu buffer de thread
			if(fplflag){
				palif++;
				buffer1[fimf] = '\0';
				tam[th] += sprintf(buffer2 + tam[th], "%s\n", buffer1 + iniciof);
			}

			//encontra o inicio da primeira palavra
			iniciop = iniciof;
			while(iniciop < fimf && (UCASE(buffer1[iniciop]) < 'A' ||
				 UCASE(buffer1[iniciop]) > 'Z')) iniciop++;

			while(iniciop < fimf){
				//encontra o fim da palavra
				fimp = iniciop;
				while(fimp < fimf && (UCASE(buffer1[fimp]) >= 'A' &&
				  	UCASE(buffer1[fimp]) <= 'Z')) fimp++;

				//soma a palavra e verifica se e palindromo
				pala++;
				pplflag = check_palavra( buffer1 + iniciop, fimp - iniciop);

				//se primo conta e salva a no buffer de saida
				if(pplflag){
					palip++;
					buffer1[fimp] = '\0';
					tam[th] += sprintf(buffer2 + tam[th], "%s\n", buffer1 + iniciop);
				}

				//encontra o inicio da proxima palavra
				iniciop = fimp;
				while(iniciop < max && (UCASE(buffer1[iniciop]) < 'A' ||
					  UCASE(buffer1[iniciop]) > 'Z')) iniciop++;
			}

			//encontra o inicio da proxima frase
			iniciof = fimf + 1;
			while(iniciof < max &&
				(buffer1[iniciof] == '\n' || buffer1[iniciof] == '\r' || buffer1[iniciof] == '.' || 
		 		buffer1[iniciof] == ':' || buffer1[iniciof] == ';' || buffer1[iniciof] == '?' ||
		 		buffer1[iniciof] == '!')) iniciof++;
		}
		
	}

	//soma os valores encontrados nesta iteracao
	palavras += pala;
	palindromos += palip;
	frases += fras;
	frasespal += palif;
}


int main(){
	int it, lido;
	int pfd, pfd_resul, j, inicio;
 	unsigned long t1, t2;

	if ((pfd = open(ARQUIVO, O_RDONLY, 0 )) == -1){
	    fprintf(stderr, "Nao foi possivel abrir: %s.\n", ARQUIVO );
	    exit(1);
	}
	if ((pfd_resul = open(ARQ_PALI, O_WRONLY | O_CREAT | O_TRUNC,
					S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
	{
	    fprintf(stderr, "Nao foi possivel abrir: %s.\n", ARQ_PALI );
	    exit(1);
	}

	t1 = clock();

	//define o numero de threads
	omp_set_num_threads(NTHREADS);	

	//zera as variaveis
	it = 0;
	palavras = palindromos = frases = frasespal = 0;

	do{
		//carrega um bloco
		lido = read(pfd, (void *) buffer1, TAM_BUFF);	
		it++;

		//processa o bloco
		busca_no_bloco(lido);

		//salva os palindromos encontrados
		for(j=0; j < NTHREADS; j++){
			inicio = 1024 * TBLOCO * j;
			write(pfd_resul, buffer2 + inicio, tam[j] - inicio);
		}

		//lseek(pfd, SEEK_CUR, iniciop - lido);

	}
	while(lido == TAM_BUFF);

	t2 = clock();

	//Imprime o relatorio
	printf("\nResultados:\n\n");
	printf("\tTempo total: %lfs\n", ((double) (t2 - t1))/CLOCKS_PER_SEC);
	printf("\tAcessos ao arquivo: %d\n", it);
	printf("\tFrases:   %d palindromos\n", frasespal);
	printf("\t          %d total\n", frases);
	printf("\tPalavras: %d palindromos\n", palindromos);
	printf("\t          %d total\n", palavras);

	close(pfd);
	close(pfd_resul);
	return 0;
}
